{
 "metadata": {
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.2-final"
  },
  "orig_nbformat": 2,
  "kernelspec": {
   "name": "python3",
   "display_name": "Python 3.8.2 64-bit",
   "metadata": {
    "interpreter": {
     "hash": "5edc29c2ed010d6458d71a83433b383a96a8cbd3efe8531bc90c4b8a5b8bcec9"
    }
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2,
 "cells": [
  {
   "source": [
    "# 廖雪峰 Python 教程"
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "source": [
    "## 3.高级特性"
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "source": [
    "### 3.4.生成器"
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "source": [
    "杨辉三角定义如下\n",
    "\n",
    "``` shell\n",
    "            1\n",
    "           / \\\n",
    "          1   1\n",
    "         / \\ / \\\n",
    "        1   2   1\n",
    "       / \\ / \\ / \\\n",
    "      1   3   3   1\n",
    "     / \\ / \\ / \\ / \\\n",
    "    1   4   6   4   1\n",
    "   / \\ / \\ / \\ / \\ / \\\n",
    "  1   5   10  10  5   1\n",
    "```"
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "def triangles():\n",
    "    n = 0\n",
    "    a = [1]\n",
    "    b = [1, 1]\n",
    "\n",
    "    while n >= 0:\n",
    "        if n == 0:\n",
    "            yield a\n",
    "            n += 1\n",
    "        elif n == 1:\n",
    "            yield b\n",
    "            n += 1\n",
    "        else:\n",
    "            c = [1] * (n + 1)\n",
    "            for i in range(1, n):\n",
    "                c[i] = b[i] + b[i - 1]  # 当前行与上一行的关系\n",
    "            yield c\n",
    "            b = c  #  当前行变成下一轮的上一行\n",
    "            n += 1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "[1]\n[1, 1]\n[1, 2, 1]\n[1, 3, 3, 1]\n[1, 4, 6, 4, 1]\n[1, 5, 10, 10, 5, 1]\n[1, 6, 15, 20, 15, 6, 1]\n[1, 7, 21, 35, 35, 21, 7, 1]\n[1, 8, 28, 56, 70, 56, 28, 8, 1]\n[1, 9, 36, 84, 126, 126, 84, 36, 9, 1]\n"
     ]
    }
   ],
   "source": [
    "n = 0\n",
    "results = []\n",
    "for t in triangles():\n",
    "    results.append(t)\n",
    "    n = n + 1\n",
    "    if n == 10:\n",
    "        break\n",
    "\n",
    "for t in results:\n",
    "    print(t)"
   ]
  },
  {
   "source": [
    "## 4.函数式编程"
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "source": [
    "### 4.1.高阶函数"
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "source": [
    "#### 4.1.1. map/reduce"
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "source": [
    "1. 利用 `map()` 函数，把用户输入的不规范的英文名字，变为首字母大写，其他小写的规范名字。输入：`['adam', 'LISA', 'barT']`，输出：`['Adam', 'Lisa', 'Bart']`："
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "metadata": {},
   "outputs": [],
   "source": [
    "def normalize(name):\n",
    "    name = name.lower()\n",
    "    name = name[0].upper() + name[1:]\n",
    "    \n",
    "    return name"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "metadata": {},
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "['Adam', 'Lisa', 'Bart']\n"
     ]
    }
   ],
   "source": [
    "\n",
    "\n",
    "# 测试:\n",
    "L1 = ['adam', 'LISA', 'barT']\n",
    "L2 = list(map(normalize, L1))\n",
    "print(L2)"
   ]
  },
  {
   "source": [
    "2. Python 提供的 `sum()` 函数可以接受一个 list 并求和，请编写一个 `prod()` 函数，可以接受一个 list 并利用 `reduce()` 求积："
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {},
   "outputs": [],
   "source": [
    "from functools import reduce\n",
    "\n",
    "def prod(L):\n",
    "    fn = lambda x, y: x * y\n",
    "    return reduce(fn, L)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "metadata": {},
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "3 * 5 * 7 * 9 = 945\n测试成功!\n"
     ]
    }
   ],
   "source": [
    "print('3 * 5 * 7 * 9 =', prod([3, 5, 7, 9]))\n",
    "if prod([3, 5, 7, 9]) == 945:\n",
    "    print('测试成功!')\n",
    "else:\n",
    "    print('测试失败!')"
   ]
  },
  {
   "source": [
    "3. 利用 `map` 和 `reduce` 编写一个 `str2float` 函数，把字符串 `'123.456'` 转换成浮点数 `123.456` ："
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "metadata": {},
   "outputs": [],
   "source": [
    "from functools import reduce\n",
    "\n",
    "\n",
    "def str2float(s):\n",
    "    s = s.split('.')\n",
    "    s_int = s[0]  # 整数部分\n",
    "    s_float = s[-1]  # 小数部分\n",
    "    s_float = s_float[-1::-1]  # 小数部分翻转\n",
    "\n",
    "    f_int = lambda x, y: 10 * x + y  # 整数计算规则\n",
    "    f_float = lambda x, y: 0.1 * x + y  # 小数部分计算规则\n",
    "    char2num = lambda s: DIGITS[s]\n",
    "\n",
    "    m = reduce(f_int, map(char2num, s_int ))\n",
    "    n = reduce(f_float, map(char2num, s_float))\n",
    "\n",
    "    return m + 0.1 * n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "metadata": {},
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "str2float('123.456') = 123.456\n测试成功!\n"
     ]
    }
   ],
   "source": [
    "DIGITS = {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, \n",
    "          '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}\n",
    "\n",
    "print('str2float(\\'123.456\\') =', str2float('123.456'))\n",
    "if abs(str2float('123.456') - 123.456) < 0.00001:\n",
    "    print('测试成功!')\n",
    "else:\n",
    "    print('测试失败!')"
   ]
  },
  {
   "source": [
    "#### 4.1.2.filter"
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "source": [
    "回数是指从左向右读和从右向左读都是一样的数，例如 `12321`，`909`。请利用`filter()` 筛选出回数："
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "source": [
    "def is_palindrome(n):\n",
    "    s = str(n)\n",
    "    index_middle = int(len(s) / 2)\n",
    "    flag = True\n",
    "    \n",
    "    for i in range(index_middle):\n",
    "        if s[i] != s[-1 - i]:\n",
    "            flag = False\n",
    "            break\n",
    "    \n",
    "    return flag"
   ],
   "cell_type": "code",
   "metadata": {},
   "execution_count": 51,
   "outputs": []
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "metadata": {},
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "1~1000: [1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 22, 33, 44, 55, 66, 77, 88, 99, 101, 111, 121, 131, 141, 151, 161, 171, 181, 191, 202, 212, 222, 232, 242, 252, 262, 272, 282, 292, 303, 313, 323, 333, 343, 353, 363, 373, 383, 393, 404, 414, 424, 434, 444, 454, 464, 474, 484, 494, 505, 515, 525, 535, 545, 555, 565, 575, 585, 595, 606, 616, 626, 636, 646, 656, 666, 676, 686, 696, 707, 717, 727, 737, 747, 757, 767, 777, 787, 797, 808, 818, 828, 838, 848, 858, 868, 878, 888, 898, 909, 919, 929, 939, 949, 959, 969, 979, 989, 999]\n测试成功!\n"
     ]
    }
   ],
   "source": [
    "# 测试:\n",
    "output = filter(is_palindrome, range(1, 1000))\n",
    "print('1~1000:', list(output))\n",
    "if list(filter(is_palindrome, range(1, 200))) == [1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 22, 33, 44, 55, 66, 77, 88, 99, 101, 111, 121, 131, 141, 151, 161, 171, 181, 191]:\n",
    "    print('测试成功!')\n",
    "else:\n",
    "    print('测试失败!')"
   ]
  },
  {
   "source": [
    "#### 4.1.3.sorted"
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "source": [
    "`L = [('Bob', 75), ('Adam', 92), ('Bart', 66), ('Lisa', 88)]`\n",
    "\n",
    "用 `sorted()` 对上述列表分别按照名字排序"
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "[('Adam', 92), ('Bart', 66), ('Bob', 75), ('Lisa', 88)]\n"
     ]
    }
   ],
   "source": [
    "def by_name(t):\n",
    "    return str.lower(t[0])\n",
    "\n",
    "\n",
    "L = [('Bob', 75), ('Adam', 92), ('Bart', 66), ('Lisa', 88)]\n",
    "L2 = sorted(L, key=by_name)\n",
    "print(L2)"
   ]
  },
  {
   "source": [
    "再按照分数降序排序"
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "[('Adam', 92), ('Lisa', 88), ('Bob', 75), ('Bart', 66)]\n"
     ]
    }
   ],
   "source": [
    "def by_score(t):\n",
    "    return - t[-1]\n",
    "\n",
    "\n",
    "L = [('Bob', 75), ('Adam', 92), ('Bart', 66), ('Lisa', 88)]\n",
    "L2 = sorted(L, key=by_score)\n",
    "print(L2)"
   ]
  },
  {
   "source": [
    "### 4.2.返回函数"
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "source": [
    "利用闭包返回一个计数器函数，每次调用它返回递增整数："
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "def createCounter():\n",
    "\n",
    "    def iterator():  # 定义一个生成器\n",
    "        c = 0\n",
    "        while True:\n",
    "            c += 1\n",
    "            yield c\n",
    "\n",
    "    g = iterator()\n",
    "\n",
    "    def counter():\n",
    "        return next(g)\n",
    "    return counter"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "1 2 3 4 5\n测试通过!\n"
     ]
    }
   ],
   "source": [
    "# 测试:\n",
    "counterA = createCounter()\n",
    "print(counterA(), counterA(), counterA(), counterA(), counterA())  # 1 2 3 4 5\n",
    "counterB = createCounter()\n",
    "if [counterB(), counterB(), counterB(), counterB()] == [1, 2, 3, 4]:\n",
    "    print('测试通过!')\n",
    "else:\n",
    "    print('测试失败!')"
   ]
  },
  {
   "source": [
    "闭包的概念还需要再复习"
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "source": [
    "### 4.3.匿名函数"
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "source": [
    "请用匿名函数改造下面的代码："
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "[1, 3, 5, 7, 9, 11, 13, 15, 17, 19]\n"
     ]
    }
   ],
   "source": [
    "def is_odd(n):ß\n",
    "    return n % 2 == 1\n",
    "\n",
    "\n",
    "L = list(filter(is_odd, range(1, 20)))\n",
    "print(L)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "[1, 3, 5, 7, 9, 11, 13, 15, 17, 19]\n"
     ]
    }
   ],
   "source": [
    "L = list(filter(lambda n: n % 2 == 1, range(1, 20)))\n",
    "print(L)"
   ]
  }
 ]
}